package net.aiion.weave;

import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;

import net.aiion.weave.spi.injection.Injectable;
import net.aiion.weave.spi.injection.InjectionContext;
import net.aiion.weave.spi.injection.InjectionService;
import net.aiion.weave.spi.injection.annotations.Inject;
import net.aiion.weave.spi.injection.annotations.Injects;
import net.aiion.weave.spi.interception.Interceptable;
import net.aiion.weave.spi.interception.InterceptionContext;
import net.aiion.weave.spi.interception.InterceptionService;
import net.aiion.weave.spi.interception.annotations.Intercepts;
import net.aiion.weave.spi.naming.Context;
import net.aiion.weave.spi.naming.Contextual;
import net.aiion.weave.spi.naming.annotations.Bound;
import net.aiion.weave.spi.naming.annotations.Named;
import net.aiion.weave.spi.naming.annotations.NotScoped;
import net.aiion.weave.spi.naming.annotations.Unbound;

@NotScoped
@Named
public class ComponentClass implements Contextual, Injectable, Interceptable
{
    @SuppressWarnings("unused")
    @Inject
    private int foo;

    @SuppressWarnings("unused")
    @Inject("a")
    private int a;

    public ComponentClass() {
    }

    public ComponentClass(int a) {
    }

    @Inject
    public void in(int a) {
    }

    @Inject
    public void in(@Inject float a) {
    }

    @Inject
    public void in(@Inject("a") double a) {
    }

    @Override
    public void setInjectionService(InjectionService aInjectionService) {
        // Inject fields, if any
        // Inject methods, if any
        try {
            foo = (int) aInjectionService.injectValue(this, int.class, ComponentClass.class.getField("foo")
                .getAnnotations());

            in((float) aInjectionService.injectValue(this, float.class,
                ComponentClass.class.getMethod("in", float.class).getParameterAnnotations()[0]));

            // ... -> InjectableComponentTransformationSink
        } catch (NoSuchFieldException | NoSuchMethodException | SecurityException e) {
            throw new RuntimeException(e);
        }
    }

    @SuppressWarnings("unused")
    private InterceptionService interceptionService;

    @Override
    public void setInterceptionService(InterceptionService aInterceptionService) {
        interceptionService = aInterceptionService;
    }

    @Deprecated
    public void interceptedMethod() {
    }

    @Override
    public void onBound(Context aNamingContext) {
        // call @Create methods
        create();
        create2();
    }

    @Override
    public void onUnbound(Context aNamingContext) {
        // call @Cleanup methods
        cleanup();
    }

    @Override
    public Class<? extends Annotation> getScope() {
        return NotScoped.class;
    }

    @Override
    public String[] getNames() {
        return new String[] {
            ComponentClass.class.getName()
        };
    }

    @Override
    public Object getValue() {
        return this;
    }

    @Bound
    public void create() {
    }

    @Bound
    public void create2() {
    }

    @Unbound
    public void cleanup() {
    }

    // Belongs to InjectionTransformationSink
    @Injects(Documented.class)
    public Object injectDocumented(InjectionContext aInjectorContext) {
        return null;
    }

    // Belongs to InterceptionTransformationSink
    @Intercepts(Inject.class)
    public void interceptSomething(InterceptionContext aInterceptorContext) {
    }
}
